/*
 * @Author: fanjs
 * @Date: 2024-03-21 16:02:00
 * @Description: 账单管理模型
 */
import { Table, Column, DataType, ForeignKey, BelongsTo } from 'sequelize-typescript'
import { Op } from 'sequelize'
import { BaseModel } from '@core/db'
import UserModel from './user'
import { Pagination, PaginationParams, PaginationResult, DateUtil } from '@core/util'

export type RateType = 'D' | 'M'

export interface BillAttributes {
  id?: number;
  userId?: number
  name: string;                  // 姓名
  phone: string;                 // 手机号码
  type: 'save' | 'borrow';       // 账单类型
  principal: number;             // 本金总额
  settledPrincipal?: number;     // 已操作本金（取款/还款）
  additionalPrincipal?: number;  // 追加本金（追存/追借）
  totalInterest?: number;        // 利息总额
  remainingInterest?: number;    // 剩余利息
  settledInterest?: number;      // 已操作利息（取息/还息）
  nextInterest?: number;         // 下次利息
  rateType?: RateType;          // 利率类型
  rate?: number;                 // 利率
  startDate: string;             // 账单开始时间
  nextDate: string;              // 下一计息日
  isSettled?: boolean;           // 是否结清
  hasRecord?: boolean;           // 有无记录
  created_at?: string;           // 创建时间
  updated_at?: string;           // 最近更新时间
}

@Table({ tableName: 'bill' })
class BillModel extends BaseModel<BillModel, BillAttributes> {
  @Column({
    type: DataType.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  })
  declare id: number

  @ForeignKey(() => UserModel)
  @Column
  declare userId: number

  @BelongsTo(() => UserModel)
  user!: UserModel

  @Column({
    type: DataType.STRING,
    comment: '姓名',
  })
  declare name: string

  @Column({
    type: DataType.STRING,
    comment: '手机号码',
  })
  declare phone: string

  @Column({
    type: DataType.ENUM('save', 'borrow'),
    comment: '账单类型',
  })
  declare type: 'save' | 'borrow'

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '本金总额',
  })
  declare principal: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '已操作本金（取款/还款）',
  })
  declare settledPrincipal: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '追加本金（追存/追借）',
  })
  declare additionalPrincipal: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '利息总额',
  })
  declare totalInterest: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '剩余利息',
  })
  declare remainingInterest: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '已操作利息（取息/还息）',
  })
  declare settledInterest: number

  @Column({
    type: DataType.DECIMAL(65, 2),
    comment: '下次利息',
  })
  declare nextInterest: number

  @Column({
    type: DataType.ENUM('D', 'M'),
    comment: '利率类型',
  })
  declare rateType: 'D' | 'M'

  @Column({
    type: DataType.DECIMAL(10, 3),
    comment: '利率',
  })
  declare rate: number

  @Column({
    type: DataType.STRING,
    comment: '账单开始时间',
  })
  declare startDate: string

  @Column({
    type: DataType.STRING,
    comment: '下一计息日',
  })
  declare nextDate: string

  @Column({
    type: DataType.BOOLEAN,
    defaultValue: false,
    comment: '是否已结清',
  })
  declare isSettled: boolean

  @Column({
    type: DataType.BOOLEAN,
    defaultValue: false,
    comment: '有无记录',
  })
  declare hasRecord: boolean

  keys() {
    this.append('updated_at', 'created_at')
  }

  /**
   * 获取账单列表
   * @param uid 用户ID
   * @param params 查询参数
   * @returns 账单列表和分页信息
   */
  static async getBillList(
    uid: number,
    params: { name?: string } & PaginationParams
  ): Promise<PaginationResult<BillModel>> {
    const { name, page, pageSize } = params;
    const where: any = { userId: uid };

    if (name) {
      where.name = {
        [Op.like]: `%${name}%`
      };
    }

    const { count, rows } = await BillModel.findAndCountAll({
      where,
      order: [['created_at', 'DESC']],
      offset: Pagination.getOffset(page, pageSize),
      limit: pageSize
    });

    // 格式化时间字段
    const formattedRows = rows.map(bill => {
      const billData = bill.toJSON();
      return {
        ...billData,
        updated_at: DateUtil.formatDateTime(billData.updated_at),
        created_at: DateUtil.formatDateTime(billData.created_at)
      };
    });

    return Pagination.createResult(count, formattedRows, { page, pageSize });
  }

  /**
   * 获取所有需要计息的账单（未结清且计息日已到）
   * @param uid 用户ID
   * @param now 当前时间
   * @returns 需要计息的账单列表
   */
  static async getBillsNeedInterest(uid: number, now: Date) {
    return await BillModel.findAll({
      where: {
        userId: uid,
        isSettled: false,
        nextDate: {
          [Op.lte]: DateUtil.formatDate(now)
        }
      },
      order: [['nextDate', 'ASC']] // 按计息日升序排序，优先处理较早的账单
    })
  }

  /**
   * 创建账单
   * @param uid 用户ID
   * @param data 账单数据
   * @returns 创建的账单
   */
  static async createBill(uid: number, data: Omit<BillAttributes, 'id' | 'userId' | 'created_at' | 'updated_at'>) {
    return await BillModel.create({
      ...data,
      userId: uid
    })
  }

  /**
   * 更新账单
   * @param uid 用户ID
   * @param id 账单ID
   * @param data 更新数据
   * @returns 更新后的账单
   */
  static async updateBill(uid: number, id: number, data: Partial<BillAttributes>) {
    const bill = await BillModel.findOne({
      where: { id, userId: uid }
    })

    if (!bill) {
      throw new Error('账单不存在')
    }

    return await bill.update(data)
  }

  /**
   * 删除账单
   * @param uid 用户ID
   * @param id 账单ID
   * @returns 是否删除成功
   */
  static async deleteBill(uid: number, id: number) {
    const bill = await BillModel.findOne({
      where: { id, userId: uid }
    })

    if (!bill) {
      throw new Error('账单不存在')
    }

    await bill.destroy()
    return true
  }

  /**
   * 获取单个账单详情
   * @param uid 用户ID
   * @param id 账单ID
   * @returns 账单详情
   */
  static async getBillDetail(uid: number, id: number) {
    const bill = await BillModel.findOne({
      where: { id, userId: uid }
    });

    if (!bill) return null;

    const billData = bill.toJSON();
    return {
      ...billData,
      created_at: DateUtil.formatDateTime(billData.created_at),
      updated_at: DateUtil.formatDateTime(billData.updated_at)
    };
  }

  /**
   * 计算剩余期限
   * @param endDate 结束日期
   * @returns 剩余天数
   */
  static calculateRemainingTerm(endDate: string) {
    return DateUtil.diffDays(new Date(), endDate) + 1
  }

  /** 
   * 计算上一个实际计息日期
   * @param nextDate 下一个计息日期
   * @param rateType 利率类型
   * @returns 上一个计息日期
   */
  static calculateLastInterestDate(nextDate: string, rateType: RateType) {
    const dateKey = rateType === 'M' ? 'month' : 'day'
    return DateUtil.addMonthsOrDays(nextDate, -1, dateKey)
  }

  /**
   * 根据ID获取账单
   * @param id 账单ID
   * @returns 账单信息 模型实例
   */
  static async getBillById(id: number) {
    const bill = await BillModel.findOne({ where: { id } });
    return bill; // 直接返回 Sequelize 模型实例
  }
}

export default BillModel 